package com.xyht.sca_s.student_manage_system.modules.trainingSchool.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample;
import com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.org.constants.UpdateTypeConstant;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.SmsTsFeeCategory;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.SmsTsJob;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.SmsTsProfession;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.req.JobBatchAddReq;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.req.JobReq;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.req.SmsTsJobReq;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.resp.SmsTsJobResp;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.entity.resp.SmsTsProfessionResp;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.mapper.SmsTsFeeCategoryMapper;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.mapper.SmsTsJobMapper;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.mapper.SmsTsProfessionMapper;
import com.xyht.sca_s.student_manage_system.modules.trainingSchool.service.SmsTsJobService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.*;

/**
 * <p>
 * 工种表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2024-05-15
 */
@Service
public class SmsTsJobServiceImpl extends ServiceImpl<SmsTsJobMapper, SmsTsJob> implements SmsTsJobService {

    @Resource
    private SmsTsProfessionMapper smsTsProfessionMapper;
    @Resource
    private SmsTsFeeCategoryMapper smsTsFeeCategoryMapper;
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    private PlatformTransactionManager platformTransactionManager;

    @Override
    public ResponseResult add(SmsTsJobReq req) {
        if (isNullOrEmpty(req.getProfessionId(), req.getCategoryId(), req.getName(), req.getCode())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsTsProfession profession = smsTsProfessionMapper.selectById(req.getProfessionId());
        if (profession == null) {
            return CommonResult.failed(CommonCodeEnum.SCHOOL_TRAINING_PROFESSION_NOT_EXIST);
        }

        SmsTsFeeCategory category = smsTsFeeCategoryMapper.selectById(req.getCategoryId());
        if (category == null) {
            return CommonResult.failed(CommonCodeEnum.SCHOOL_TRAINING_FEE_CATEGORY_NOT_EXIST);
        }

        // 查询是否有重复数据
        int count = this.count(new LambdaQueryWrapper<SmsTsJob>()
//                .eq(SmsTsJob::getProfessionId, req.getProfessionId())
//                .eq(SmsTsJob::getCategoryId, req.getCategoryId())
//                .eq(SmsTsJob::getCode, req.getCode())
                .eq(SmsTsJob::getName, req.getName()));
        if (count > 0) {
            return CommonResult.failed(CommonCodeEnum.DATA_EXIST);
        }

        SmsTsJob job = new SmsTsJob();
        BeanUtils.copyProperties(req, job);
        job.setIsSecond(req.getIsSecond() == null ? false : req.getIsSecond());
        this.save(job);

        return CommonResult.success();
    }

    @Override
    public ResponseResult list(Integer pageNum, Integer pageSize, String professionId, String ss) {
        LambdaQueryWrapper<SmsTsJob> queryWrapper = new LambdaQueryWrapper<SmsTsJob>()
                .orderByAsc(SmsTsJob::getCode);

        if (!isNullOrEmpty(professionId)) {
            queryWrapper.eq(SmsTsJob::getProfessionId, professionId);
        }

        if (!isNullOrEmpty(ss)) {
            List<SmsTsProfession> professionList = smsTsProfessionMapper.selectList(new LambdaQueryWrapper<SmsTsProfession>()
                    .like(SmsTsProfession::getName, ss));
            List<String> professionIdList = professionList.stream().map(SmsTsProfession::getId).collect(Collectors.toList());

            queryWrapper.like(SmsTsJob::getName, ss)
                    .or().in(SmsTsJob::getProfessionId, professionIdList.isEmpty() ? Collections.singletonList("") : professionIdList);
        }

        Page<SmsTsJob> page = new Page<>(pageNum, pageSize);
        this.page(page, queryWrapper);
        List<SmsTsJobResp> collect = page.getRecords().stream().map(item -> {
            SmsTsJobResp resp = new SmsTsJobResp();
            BeanUtils.copyProperties(item, resp);
            SmsTsProfession profession = smsTsProfessionMapper.selectById(item.getProfessionId());
            if (profession != null) {
                resp.setProfessionName(profession.getName());
            }

            SmsTsFeeCategory category = smsTsFeeCategoryMapper.selectById(item.getCategoryId());
            if (category != null) {
                resp.setCategoryName(category.getName());
            }

            return resp;
        }).collect(Collectors.toList());

        return CommonResult.success(collect, (int) page.getTotal());
    }

    @Override
    @Async
    public Future<ResponseResult> batchAddJob(JobBatchAddReq req, String userId) {
        // 1. 校验参数
        if (isNullOrEmpty(req.getType(), req.getJobReqList())) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        // 2. 创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TaskNameExample.TASK_NAME_JOB_IMPORT);
        smsImportTask.setUserId(userId);
        smsImportTask.setStatus(TASK_STATUS_DOING); // 任务状态 0:进行中
        smsImportTask.setTaskType(TaskTypeConstant.TASK_TYPE_JOB_IMPORT);
        smsImportTaskMapper.insert(smsImportTask);
        String taskId = smsImportTask.getId();
        if (isNullOrEmpty(taskId)) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        // 3. 获取导入数据循环导入
        List<JobReq> jobReqList = req.getJobReqList();
        int OFFSET_ROW = 1; // 初始化行数
        int taskStatus = TASK_STATUS_DONE; // 任务状态: 完成
        for (int i = 0; i < jobReqList.size(); i++) {
            // 3.1 开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = platformTransactionManager.getTransaction(dt);
            try {
                // 3.2 获取本条导入数据
                JobReq jobReq = jobReqList.get(i);

                // 3.3 校验参数并获取导入信息
                // 必填字段验证(行业名/类别名/工种名/工种编码)
                if (isNullOrEmpty(jobReq.getProfessionName(), jobReq.getCategoryName(), jobReq.getName(), jobReq.getCode())) {
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(jobReq.getProfessionName(), jobReq.getName(), taskId, REASON_INVALID_PARAM, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }

                SmsTsProfession profession = smsTsProfessionMapper.selectOne(new LambdaQueryWrapper<SmsTsProfession>()
                        .eq(SmsTsProfession::getName, jobReq.getProfessionName()));
                if (profession == null) {
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(jobReq.getName(), jobReq.getProfessionName(), taskId, REASON_PROFESSION_NOT_EXIST, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }

                SmsTsFeeCategory category = smsTsFeeCategoryMapper.selectOne(new LambdaQueryWrapper<SmsTsFeeCategory>()
                        .eq(SmsTsFeeCategory::getName, jobReq.getCategoryName()));
                if (category == null) {
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(jobReq.getName(), jobReq.getCategoryName(), taskId, REASON_FEE_CATEGORY_NOT_EXIST, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }

                jobReq.setIsSecond(jobReq.getIsSecond() == null ? false : jobReq.getIsSecond());

                // 3.4 根据添加类型添数据
                switch (req.getType()) {
                    case UpdateTypeConstant.UPDATE_TYPE_UPDATE_ADD: // 3.4.1 更新添加
                        // 3.4.1.1 查询是否存在
                        SmsTsJob job = this.getOne(new LambdaQueryWrapper<SmsTsJob>()
                                .eq(SmsTsJob::getName, jobReq.getName()));

                        // 3.4.1.2 添加数据
                        if (job != null) { // 存在进行修改
                            BeanUtils.copyProperties(jobReq, job);
                            job.setProfessionId(profession.getId());
                            job.setCategoryId(category.getId());

                            // 修改
                            this.updateById(job);
                        } else { // 不存在进行新增
                            job = new SmsTsJob();
                            BeanUtils.copyProperties(jobReq, job);
                            job.setProfessionId(profession.getId());
                            job.setCategoryId(category.getId());

                            // 保存
                            this.save(job);
                        }

                        break;
                    case UpdateTypeConstant.UPDATE_TYPE_COVER_ADD: // 3.4.2 覆盖添加
                        // 3.4.2.1 删除原有数据
                        this.remove(new LambdaQueryWrapper<SmsTsJob>()
                                .eq(SmsTsJob::getName, jobReq.getName()));

                        // 3.4.2.2 添加数据
                        SmsTsJob newJob = new SmsTsJob();
                        BeanUtils.copyProperties(jobReq, newJob);
                        newJob.setProfessionId(profession.getId());
                        newJob.setCategoryId(category.getId());

                        // 保存
                        this.save(newJob);

                        break;
                }

                // 3.5 提交事务
                platformTransactionManager.commit(status);
            } catch (Exception e) {
                e.printStackTrace();
                // 捕捉到异常回滚事务
                platformTransactionManager.rollback(status);
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    platformTransactionManager.commit(status);
                }
            }
        }

        // 4. 更新任务状态为已结束
        smsImportTask.setStatus(taskStatus);
        smsImportTaskMapper.updateById(smsImportTask);

        return null;
    }

    @Override
    public ResponseResult tree(String professionId, String ss) {
        LambdaQueryWrapper<SmsTsJob> queryWrapper = new LambdaQueryWrapper<>();
        if (professionId != null) {
            queryWrapper.eq(SmsTsJob::getProfessionId, professionId);
        }

        if (!isNullOrEmpty(ss)) {
            List<SmsTsProfession> professionList = smsTsProfessionMapper.selectList(new LambdaQueryWrapper<SmsTsProfession>()
                    .like(SmsTsProfession::getName, ss));
            List<String> professionIdList = professionList.stream().map(SmsTsProfession::getId).collect(Collectors.toList());

            queryWrapper.and(i -> i.like(SmsTsJob::getName, ss)
                    .or().in(SmsTsJob::getProfessionId, professionIdList.isEmpty() ? Collections.singletonList("") : professionIdList));
        }

        List<SmsTsJob> jobList = this.list(queryWrapper);
        List<String> professionIdList = jobList.stream().map(SmsTsJob::getProfessionId).distinct().collect(Collectors.toList());

        List<SmsTsProfessionResp> professionRespList = new ArrayList<>();
        for (String proId : professionIdList) {
            SmsTsProfession profession = smsTsProfessionMapper.selectById(proId);
            if (profession == null) {
                continue;
            }

            SmsTsProfessionResp professionResp = new SmsTsProfessionResp();
            BeanUtils.copyProperties(profession, professionResp);
            List<SmsTsJobResp> jobRespList = jobList.stream().filter(job -> job.getProfessionId().equals(profession.getId()))
                    .map(job -> {
                        SmsTsJobResp jobResp = new SmsTsJobResp();
                        BeanUtils.copyProperties(job, jobResp);
                        return jobResp;
                    }).collect(Collectors.toList());
            professionResp.setJobRespList(jobRespList);
            professionRespList.add(professionResp);
        }

        if (professionRespList.size() > 0) {
            professionRespList.sort(Comparator.comparing(SmsTsProfessionResp::getCode));
        }

        return CommonResult.success(professionRespList);
    }

    @Override
    public ResponseResult update(SmsTsJobReq req) {
        if (isNullOrEmpty(req.getId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsTsJob job = this.getById(req.getId());
        if (job == null) {
            return CommonResult.failed(CommonCodeEnum.SCHOOL_TRAINING_JOB_NOT_EXIST);
        }

        BeanUtils.copyProperties(req, job);
        this.updateById(job);

        return CommonResult.success();
    }

    /**
     * 创建错误
     *
     * @param no     学号
     * @param name   姓名
     * @param taskId 任务id
     * @param reason 错误原因
     * @param row    错误行数
     */
    private void createImportTaskDetail(String no, String name, String taskId, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(taskId); // 任务id
        smsImportTaskDetail.setFailReason(reason); // 错误原因
        smsImportTaskDetail.setFailName(name); // 姓名
        smsImportTaskDetail.setFailNo(no); // 学号
        smsImportTaskDetail.setFailRow(row); // 错误行数
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }
}
